﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using System.IO;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.Decompiler.Ast;
using System.Reflection;

namespace devtm.Aop.Extensions
{
    
    public static class AssemblyDefinitionExt
    {


        #region Load

        public static Assembly LoadAssemblyInMemory(this AssemblyDefinition ass, AppDomain appDomain, bool generateScript)
        {

            Assembly assembly = null;

            //if (generateScript)
            //    GenerateScript(ass);



            if (generateScript)
            {
                string path = Environment.CurrentDirectory;
                string filename = Path.Combine(path, ass.Name.Name) + ".dll";
                MemoryStream streamSymbol = new MemoryStream();

                var parameters = new WriterParameters
                {
                    WriteSymbols = true,
                    SymbolStream = streamSymbol,
                    SymbolWriterProvider = new Mono.Cecil.Pdb.PdbWriterProvider()
                };

                ass.Write(filename, parameters);
                assembly = Assembly.LoadFile(filename);
            }

            else
            {
                MemoryStream streamAssembly = new MemoryStream();
                var parameters = new WriterParameters { WriteSymbols = false };
                ass.Write(streamAssembly, parameters);
                byte[] assemblyArray = streamAssembly.ToArray();
                assembly = appDomain.Load(assemblyArray);
            }

            return assembly;

        }

        private static void GenerateScript(AssemblyDefinition ass)
        {

            GetCode(ass);

        }

        public static void GetCode(AssemblyDefinition m1)
        {

            ModuleDefinition _module = m1.MainModule;
            DecompilerContext context = new DecompilerContext(_module);
            ILAstBuilder ils = new ILAstBuilder();
            List<ILNode> operations;
            StringWriter w = new StringWriter();

            var t1 = new OutputVisitor(w, new CSharpFormattingOptions());


            AstBuilder builder = new AstBuilder(new DecompilerContext(_module))
            {
                DecompileMethodBodies = true
            };


            foreach (TypeDefinition type in _module.Types)
            {
                try
                {
                    builder.AddType(type);
                }
                catch (Exception ex)
                {

                    throw;
                }

                context.CurrentType = type;

                foreach (MethodDefinition method in type.Methods)
                {

                    operations = ils.Build(method, true);

                    BlockStatement iop = AstMethodBodyBuilder.CreateMethodBody(method, context);

                    iop.AcceptVisitor(t1, null);

                }
            }

        }

        #endregion



    }
}
